#include "execution/catalog.h"
#include "storage/buffer_pool.h"
#include <fstream>
#include <sstream>
#include <iostream>

Catalog::Catalog(std::unique_ptr<BufferPool> bufferPool)
    : bufferPool(std::move(bufferPool)) {
    loadFromStorage();
}

Catalog::~Catalog() {
    saveToStorage();
}

bool Catalog::createTable(const TableInfo& tableInfo) {
    if (tables.find(tableInfo.name) != tables.end()) {
        return false; // Already exists
    }
    
    tables[tableInfo.name] = tableInfo;
    return saveToStorage();
}

bool Catalog::dropTable(const std::string& tableName) {
    auto it = tables.find(tableName);
    if (it == tables.end()) {
        return false; // Table does not exist
    }
    
    tables.erase(it);
    return saveToStorage();
}

// Helper function: Compare strings case-insensitively
bool equalsIgnoreCase(const std::string& a, const std::string& b) {
    if (a.length() != b.length()) return false;
    for (size_t i = 0; i < a.length(); ++i) {
        if (tolower(a[i]) != tolower(b[i])) return false;
    }
    return true;
}

TableInfo* Catalog::getTable(const std::string& tableName) {
    // 不区分大小写查找表
    for (auto& pair : tables) {
        if (equalsIgnoreCase(pair.first, tableName)) {
            return &pair.second;
        }
    }
    return nullptr;
}

std::vector<TableInfo> Catalog::getAllTables() {
    std::vector<TableInfo> result;
    for (const auto& pair : tables) {
        result.push_back(pair.second);
    }
    return result;
}

bool Catalog::loadFromStorage() {
    std::ifstream file("catalog.dat");
    if (!file.is_open()) {
        return true; // No existing catalog
    }
    
    tables.clear();
    std::string line;
    while (std::getline(file, line)) {
        if (line.empty()) continue;
        
        TableInfo tableInfo;
        std::stringstream ss(line);
        ss >> tableInfo.name >> tableInfo.firstPageId;
        
        int columnCount;
        ss >> columnCount;
        for (int i = 0; i < columnCount; ++i) {
            ColumnInfo column;
            ss >> column.name >> column.type >> column.length;
            tableInfo.columns.push_back(column);
        }
        
        tables[tableInfo.name] = tableInfo;
    }
    
    file.close();
    return true;
}

bool Catalog::saveToStorage() {
    std::ofstream file("catalog.dat");
    if (!file.is_open()) {
        std::cerr << "Failed to open catalog file for writing" << std::endl;
        return false;
    }
    
    for (const auto& pair : tables) {
        const TableInfo& tableInfo = pair.second;
        file << tableInfo.name << " " << tableInfo.firstPageId << " " << tableInfo.columns.size();
        
        for (const auto& column : tableInfo.columns) {
            file << " " << column.name << " " << column.type << " " << column.length;
        }
        
        file << std::endl;
    }
    
    file.close();
    return true;
}

std::unique_ptr<BufferPool>& Catalog::getBufferPool() {
    return bufferPool;
}